package myjwt

import (
	"fmt"
	"github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"
	"net/http"
	"strings"
	"time"
)

//自定义结构体  保存你要放在token中的信息的类型
type MyClaims struct {
	Username string `json:"username"`
	jwt.StandardClaims
}

//定义生效时间（当前时间一分钟前） 持续到当前时间2小时后 使用者fyd
var Begin_time int64 = time.Now().Unix() - 60
var End_time int64 = time.Now().Unix() + 60*60*2
var username string = "fyd"
var mySignKey = []byte("woshidashuaige")

func Get_token(user string) string {
	//创建这个自定义对象的类
	c := MyClaims{
		Username: user, //存在token中的信息
		StandardClaims: jwt.StandardClaims{
			NotBefore: Begin_time,
			ExpiresAt: End_time,
			Issuer:    username,
		},
	}
	//将这个对象进行加密 得到token
	t := jwt.NewWithClaims(jwt.SigningMethodHS256, c)
	//分别是头 体 加密串
	//&{ 0xc000004120 map[alg:HS256 typ:JWT] {zsq { 1652948353  0 fyd 1652941093 }}  false}
	//fmt.Println(t)
	//对token进行加密  返回token字符串 和错误
	s, err := t.SignedString(mySignKey)
	if err != nil {
		fmt.Println("token 加密出错", err)
	}
	//这样 就已经生成成功了

	return s
}
func Analysis_token(s string) (string, error) {
	//从前端返回token字符串后进行解析 生成token
	// 这个函数的 参数的意思 将前端返回的token字符串拿到 将token的格式获取 再通过一个方法得到当时加密token的秘钥
	token, err := jwt.ParseWithClaims(s, &MyClaims{}, func(token *jwt.Token) (interface{}, error) {
		return mySignKey, nil
	})
	if err != nil {
		fmt.Println("token 解密失败/token 过期 ：", err)
		return "", err
	}
	//fmt.Println(token)
	//fmt.Println(token.Claims.(*MyClaims)) //得到之前那个自定义对象
	username := token.Claims.(*MyClaims).Username
	//fmt.Println(token.Claims.(*MyClaims).Username) //得到之前那个自定义对象的属性
	return username, nil
}

func JWTAuthMiddleware() func(c *gin.Context) {
	return func(c *gin.Context) {
		// 客户端携带Token有三种方式 1.放在请求头 2.放在请求体 3.放在URI
		// Token放在Header的Authorization中，并使用Bearer开头
		authHeader := c.Request.Header.Get("Authorization")
		if authHeader == "" {
			c.JSON(http.StatusOK, gin.H{
				"code": 2003,
				"msg":  "请求头中auth为空",
			})
			c.Abort()
			return
		}
		// 按空格分割
		parts := strings.SplitN(authHeader, " ", 2)
		if !(len(parts) == 2 && parts[0] == "Bearer") {
			c.JSON(http.StatusOK, gin.H{
				"code": 2004,
				"msg":  "请求头中auth格式有误",
			})
			c.Abort()
			return
		}
		// parts[1]是获取到的tokenString，我们使用之前定义好的解析JWT的函数来解析它
		mc, err := Analysis_token(parts[1])
		if err != nil {
			c.JSON(http.StatusOK, gin.H{
				"code": 2005,
				"msg":  "登录失效请重新登录", //无效的token
			})
			c.Abort()
			return
		}
		// 将当前请求的信息保存到请求的上下文c上
		c.Set("userId", mc)
		c.Next() // 后续的处理函数可以用过c.Get("userId")来获取当前请求的用户信息
	}
}
